/********************************************************************************
 * Project Name		[JavaEE_Web]
 * File Name     	[ReflectionUtils.java]
 * Creation Date 	[2015-01-01]
 * 
 * Copyright© ge.y.yang@gmail.com All Rights Reserved
 * 
 * Work hard, play harder, think big and keep fit
 ********************************************************************************/
package mvc.utils;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
 * 反射工具类
 * 
 * @author 不落的太阳(Sean Yang aka ShortPeace)
 * @version 1.0
 * @since jdk 1.8
 * 
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public class ReflectionUtils {

	/**
	 * 通过反射, 获得classType的父类的泛型参数类型
	 * 
	 * @param classType
	 *            子类类型
	 * @param index
	 *            第几个泛型参数
	 * @return
	 */
	public static Class getSuperClassGenericType(Class classType, int index) {
		// getGenericSuperclass()获得带有泛型参数的父类
		Type genericType = classType.getGenericSuperclass();

		// 如果genericType不是带泛型类型的参数, 直接返回Object.class
		if (!(genericType instanceof ParameterizedType)) {
			return Object.class;
		}

		// 获得泛型类型的参数
		Type[] params = ((ParameterizedType) genericType).getActualTypeArguments();

		// 如果要查询的参数索引不符合条件, 直接返回Object.class
		if (index >= params.length || index < 0) {
			return Object.class;
		}

		if (!(params[index] instanceof Class)) {
			return Object.class;
		}

		return (Class) params[index];
	}

	/**
	 * 通过反射, 获得classType的父类的泛型参数类型
	 * 
	 * @param classType
	 *            子类类型
	 * @return
	 */
	public static <T> Class<T> getSuperClassGenericType(Class classType) {
		return getSuperClassGenericType(classType, 0);
	}

	/**
	 * 获得对象指定方法名称和参数列表的方法, 从子类到父类寻找
	 * 
	 * @param object
	 *            指定对象
	 * @param methodName
	 *            要查询的方法
	 * @param parameterTypes
	 *            方法的参数类型
	 * @return
	 */
	public static Method getDeclaredMethod(Object object, String methodName, Class<?>... parameterTypes) {

		for (Class<?> currentClass = object.getClass(); currentClass != Object.class; currentClass = currentClass
				.getSuperclass()) {
			try {
				return currentClass.getDeclaredMethod(methodName, parameterTypes);
			} catch (NoSuchMethodException | SecurityException e) {
				// Method不在当前类定义, 继续向上转型
			}
		}

		return null;
	}

	/**
	 * 获取对象指定的属性, 从子类到父类寻找
	 * 
	 * @param object
	 * @param fieldName
	 * @return
	 */
	public static Field getDeclaredField(Object object, String fieldName) {

		for (Class<?> currentClass = object.getClass(); currentClass != Object.class; currentClass = currentClass
				.getSuperclass()) {
			try {
				return currentClass.getDeclaredField(fieldName);
			} catch (NoSuchFieldException | SecurityException e) {
				// Field不在当前类定义, 继续向上转型
			}
		}

		return null;
	}

	/**
	 * 使属性变得可访问
	 * 
	 * @param filed
	 */
	public static void enableAccess(Field field) {
		if (!Modifier.isPublic(field.getModifiers())) {
			field.setAccessible(true);
		}
	}

	/**
	 * 调用方法
	 * 
	 * @param object
	 *            要调用方法的对象
	 * @param methodName
	 *            要调用方法的名称
	 * @param parameterTypes
	 *            要调用方法的参数类型
	 * @param parameters
	 *            要调用方法的参数值
	 * @return
	 */
	public static Object invokeMethod(Object object, String methodName, Class<?>[] parameterTypes,
			Object[] parameters) {
		Method method = getDeclaredMethod(object, methodName, parameterTypes);

		if (method == null) {
			throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + object + "]");
		}

		method.setAccessible(true);

		try {
			return method.invoke(object, parameters);
		} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
		}
		return null;
	}

	/**
	 * 设置对象指定属性的值
	 * 
	 * @param object
	 *            要设置属性值的对象
	 * @param fieldName
	 *            要设置的属性名
	 * @param fieldValue
	 *            要设置的属性值
	 */
	public static void setFieldValue(Object object, String fieldName, Object fieldValue) {
		Field field = getDeclaredField(object, fieldName);

		if (field == null) {
			throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
		}

		enableAccess(field);

		try {
			field.set(object, fieldValue);
		} catch (IllegalArgumentException | IllegalAccessException e) {
		}
	}

	/**
	 * 获取对象指定属性的值
	 * 
	 * @param object
	 *            要获取属性值的对象
	 * @param fieldName
	 *            要获取的属性值名称
	 * @return
	 */
	public static Object getFieldValue(Object object, String fieldName) {
		Field field = getDeclaredField(object, fieldName);

		if (field == null) {
			throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
		}

		enableAccess(field);

		try {
			return field.get(object);
		} catch (IllegalArgumentException | IllegalAccessException e) {
		}

		return null;
	}
}
